From: kfraser@localhost.localdomain Date: Thu, 27 Jul 2006 12:05:33 +0000 (+0100) Subject: [HVM][VMX] Fix injection of software exceptions (#BP,#OF) X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~15786^2~1^2~8 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/success//%22http:/www.example.com/cgi/success/?a=commitdiff_plain;h=9684bace621f325a7ecafa099fe5b15df0d0b207;p=xen.git [HVM][VMX] Fix injection of software exceptions (#BP,#OF) From: George Dunlap Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 918d7c5587..fe00954a0a 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -286,7 +286,7 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) if ( msr_content & ~(EFER_LME | EFER_LMA | EFER_NX | EFER_SCE) ) { printk("trying to set reserved bit in EFER\n"); - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); return 0; } @@ -300,7 +300,7 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) { printk("trying to set LME bit when " "in paging mode or PAE bit is not set\n"); - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); return 0; } @@ -318,7 +318,7 @@ static inline int long_mode_do_msr_write(struct cpu_user_regs *regs) if ( !IS_CANO_ADDRESS(msr_content) ) { HVM_DBG_LOG(DBG_LEVEL_1, "Not cano address of msr write\n"); - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); return 0; } @@ -1438,7 +1438,7 @@ static int vmx_set_cr0(unsigned long value) &v->arch.hvm_vmx.cpu_state) ) { HVM_DBG_LOG(DBG_LEVEL_1, "Enable paging before PAE enabled\n"); - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); } if ( test_bit(VMX_CPU_STATE_LME_ENABLED, @@ -1520,7 +1520,7 @@ static int vmx_set_cr0(unsigned long value) { if ( value & X86_CR0_PG ) { /* inject GP here */ - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); return 0; } else { /* @@ -1764,7 +1764,7 @@ static int mov_to_cr(int gp, int cr, struct cpu_user_regs *regs) else { if ( test_bit(VMX_CPU_STATE_LMA_ENABLED, &v->arch.hvm_vmx.cpu_state) ) - vmx_inject_exception(v, TRAP_gp_fault, 0); + vmx_inject_hw_exception(v, TRAP_gp_fault, 0); clear_bit(VMX_CPU_STATE_PAE_ENABLED, &v->arch.hvm_vmx.cpu_state); } @@ -2192,7 +2192,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) if ( test_bit(_DOMF_debugging, &v->domain->domain_flags) ) domain_pause_for_debugger(); else - vmx_inject_exception(v, TRAP_int3, VMX_DELIVER_NO_ERROR_CODE); + vmx_reflect_exception(v); break; } #endif @@ -2219,7 +2219,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) /* * Inject #PG using Interruption-Information Fields */ - vmx_inject_exception(v, TRAP_page_fault, regs.error_code); + vmx_inject_hw_exception(v, TRAP_page_fault, regs.error_code); v->arch.hvm_vmx.cpu_cr2 = va; TRACE_3D(TRC_VMX_INT, v->domain->domain_id, TRAP_page_fault, va); } @@ -2335,7 +2335,7 @@ asmlinkage void vmx_vmexit_handler(struct cpu_user_regs regs) case EXIT_REASON_VMON: /* Report invalid opcode exception when a VMX guest tries to execute any of the VMX instructions */ - vmx_inject_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE); + vmx_inject_hw_exception(v, TRAP_invalid_op, VMX_DELIVER_NO_ERROR_CODE); break; default: diff --git a/xen/include/asm-x86/hvm/vmx/vmx.h b/xen/include/asm-x86/hvm/vmx/vmx.h index 9e9dd90f32..f8fe619ede 100644 --- a/xen/include/asm-x86/hvm/vmx/vmx.h +++ b/xen/include/asm-x86/hvm/vmx/vmx.h @@ -143,11 +143,12 @@ extern unsigned int cpu_rev; */ #define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */ #define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */ -#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */ +#define INTR_INFO_DELIVER_CODE_MASK 0x800 /* 11 */ #define INTR_INFO_VALID_MASK 0x80000000 /* 31 */ #define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */ -#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */ +#define INTR_TYPE_HW_EXCEPTION (3 << 8) /* hardware exception */ +#define INTR_TYPE_SW_EXCEPTION (6 << 8) /* software exception */ /* * Exit Qualifications for MOV for Control Register Access @@ -421,7 +422,7 @@ static inline int vmx_pgbit_test(struct vcpu *v) } static inline int __vmx_inject_exception(struct vcpu *v, int trap, int type, - int error_code) + int error_code, int ilen) { unsigned long intr_fields; @@ -429,22 +430,33 @@ static inline int __vmx_inject_exception(struct vcpu *v, int trap, int type, intr_fields = (INTR_INFO_VALID_MASK | type | trap); if (error_code != VMX_DELIVER_NO_ERROR_CODE) { __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); - intr_fields |= INTR_INFO_DELIEVER_CODE_MASK; + intr_fields |= INTR_INFO_DELIVER_CODE_MASK; } - + + if(ilen) + __vmwrite(VM_ENTRY_INSTRUCTION_LEN, ilen); + __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields); return 0; } -static inline int vmx_inject_exception(struct vcpu *v, int trap, int error_code) +static inline int vmx_inject_hw_exception(struct vcpu *v, int trap, int error_code) { v->arch.hvm_vmx.vector_injected = 1; - return __vmx_inject_exception(v, trap, INTR_TYPE_EXCEPTION, error_code); + return __vmx_inject_exception(v, trap, INTR_TYPE_HW_EXCEPTION, + error_code, 0); +} + +static inline int vmx_inject_sw_exception(struct vcpu *v, int trap, int instruction_len) { + v->arch.hvm_vmx.vector_injected=1; + return __vmx_inject_exception(v, trap, INTR_TYPE_SW_EXCEPTION, + VMX_DELIVER_NO_ERROR_CODE, + instruction_len); } static inline int vmx_inject_extint(struct vcpu *v, int trap, int error_code) { - __vmx_inject_exception(v, trap, INTR_TYPE_EXT_INTR, error_code); + __vmx_inject_exception(v, trap, INTR_TYPE_EXT_INTR, error_code, 0); __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0); return 0; @@ -452,14 +464,14 @@ static inline int vmx_inject_extint(struct vcpu *v, int trap, int error_code) static inline int vmx_reflect_exception(struct vcpu *v) { - int error_code, vector; + int error_code, intr_info, vector; - __vmread(VM_EXIT_INTR_INFO, &vector); - if (vector & INTR_INFO_DELIEVER_CODE_MASK) + __vmread(VM_EXIT_INTR_INFO, &intr_info); + vector = intr_info & 0xff; + if (intr_info & INTR_INFO_DELIVER_CODE_MASK) __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code); else error_code = VMX_DELIVER_NO_ERROR_CODE; - vector &= 0xff; #ifndef NDEBUG { @@ -472,7 +484,19 @@ static inline int vmx_reflect_exception(struct vcpu *v) } #endif /* NDEBUG */ - vmx_inject_exception(v, vector, error_code); + /* According to Intel Virtualization Technology Specification for + the IA-32 Intel Architecture (C97063-002 April 2005), section + 2.8.3, SW_EXCEPTION should be used for #BP and #OV, and + HW_EXCPEPTION used for everything else. The main difference + appears to be that for SW_EXCEPTION, the EIP/RIP is incremented + by VM_ENTER_INSTRUCTION_LEN bytes, whereas for HW_EXCEPTION, + it is not. */ + if((intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_SW_EXCEPTION) { + int ilen; + __vmread(VM_EXIT_INSTRUCTION_LEN, &ilen); + vmx_inject_sw_exception(v, vector, ilen); + } else + vmx_inject_hw_exception(v, vector, error_code); return 0; }